﻿using System;
using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using STeaL.Algorithm;

namespace Test {

  [TestClass]
  public class IListTest_1 {
    public IListTest_1() {}

    private TestContext testContextInstance;

    /// <summary>
    ///現在のテストの実行についての情報および機能を
    ///提供するテスト コンテキストを取得または設定します。
    ///</summary>
    public TestContext TestContext {
      get { return testContextInstance; }
      set { testContextInstance = value; }
    }

    #region 追加のテスト属性
    // クラス内で最初のテストを実行する前に、ClassInitialize を使用してコードを実行してください
    [ClassInitialize()]
    public static void MyClassInitialize(TestContext testContext) { }

    // クラス内のテストをすべて実行したら、ClassCleanup を使用してコードを実行してください
    [ClassCleanup()]
    public static void MyClassCleanup() { }

    // 各テストを実行する前に、TestInitialize を使用してコードを実行してください
    [TestInitialize()]
    public void TestInitialize() { c = new List<int>(); }

    // 各テストを実行した後に、TestCleanup を使用してコードを実行してください
    [TestCleanup()]
    public void MyTestCleanup() { }
    #endregion

    [TestMethod]
    public void front() {
      c.clear();
      c.push_front(10);
      Assert.AreEqual(10, c.front());
      c.assign(new int[] { 0, 1, 2, 3, 4 });
      Assert.AreEqual(0, c.front());
      c.push_front(-1);
      Assert.AreEqual(6, c.size());
      Assert.AreEqual(-1, c.front());
      c.pop_front();
      Assert.AreEqual(0, c.front());
      Assert.AreEqual(5, c.size());
    }

    [TestMethod]
    public void back() {
      c.clear();
      c.push_back(10);
      Assert.AreEqual(10, c.back());
      c.assign(new int[] { 0, 1, 2, 3, 4 });
      Assert.AreEqual(4, c.back());
      c.push_back(-1);
      Assert.AreEqual(6, c.size());
      Assert.AreEqual(-1, c.back());
      c.pop_back();
      Assert.AreEqual(4, c.back());
      Assert.AreEqual(5, c.size());
    }

    [TestMethod]
    public void resize() {
      int i;
      c.assign(new int[] { 0, 1, 2, 3, 4 });
      c.resize(10);
      i = 0;
      foreach (int n in c) { Assert.AreEqual(i < 5 ? i : default(int), n); ++i; }
      c.resize(3);
      Assert.AreEqual(3, c.size());
      i = 0;
      foreach( int n in c ) { Assert.AreEqual(i, n); ++i; }
      c.resize(10,-1);
      Assert.AreEqual(10, c.size());
      i = 0;
      foreach (int n in c) { Assert.AreEqual(i < 3 ? i : -1, n); ++i; }
    }

    [TestMethod]
    public void insert() {
      c.insert(0,1);
      Assert.AreEqual(1, c[0]);
      c.assign(new int[] { 0, 2, 4, 6, 8 });
      c.insert(1,1);
      Assert.AreEqual(0, c[0]);
      Assert.AreEqual(1, c[1]);
      Assert.AreEqual(2, c[2]);
      c.assign(new int[] { 0, 2, 4, 6, 8 });
      c.insert(1, 2, 1);
      Assert.AreEqual(0, c[0]);
      Assert.AreEqual(1, c[1]);
      Assert.AreEqual(1, c[2]);
      Assert.AreEqual(2, c[3]);
      c.assign(new int[] { 0, 2, 4, 6, 8 });
      c.insert(1, new int[] { 1, 3});
      Assert.AreEqual(0, c[0]);
      Assert.AreEqual(1, c[1]);
      Assert.AreEqual(3, c[2]);
      Assert.AreEqual(2, c[3]);
    }

    [TestMethod]
    public void erase() {
      c.assign(new int[] { 0, 1, 2, 3, 4 });
      c.erase(1);
      Assert.AreEqual(0, c[0]);
      Assert.AreEqual(2, c[1]);
      Assert.AreEqual(4, c.size());
      c.assign(new int[] { 0, 1, 2, 3, 4 });
      c.erase(1,4);
      Assert.AreEqual(0, c[0]);
      Assert.AreEqual(4, c[1]);
      Assert.AreEqual(2, c.size());
    }

    [TestMethod]
    public void reverse() {
      int i;
      c.assign(new int[] { 3, 2, 1, 0 });
      c.reverse();
      Assert.AreEqual(4, c.size());
      i = 0;
      foreach( int n in c ) Assert.AreEqual(i++, n);
      c.assign(new int[] { 4, 3, 2, 1, 0 });
      c.reverse();
      Assert.AreEqual(5, c.size());
      i = 0;
      foreach (int n in c) Assert.AreEqual(i++, n);
    }

    [TestMethod]
    public void lower_bound() {
      c.assign(new int[] { 2,2,4,4,6,6,8,8});
      Assert.AreEqual(0, c.lower_bound(1, (x,y) => x < y ));
      Assert.AreEqual(0, c.lower_bound(2, (x,y) => x < y));
      Assert.AreEqual(2, c.lower_bound(3, (x,y) => x < y));
      Assert.AreEqual(c.Count, c.lower_bound(10, (x, y) => x < y));
    }

    [TestMethod]
    public void upper_bound() {
      c.assign(new int[] { 2, 2, 4, 4, 6, 6, 8, 8 });
      Assert.AreEqual(0, c.upper_bound(1, (x, y) => x < y));
      Assert.AreEqual(2, c.upper_bound(2, (x, y) => x < y));
      Assert.AreEqual(2, c.upper_bound(3, (x, y) => x < y));
      Assert.AreEqual(c.Count, c.upper_bound( 8, (x, y) => x < y));
      Assert.AreEqual(c.Count, c.upper_bound(10, (x, y) => x < y));
    }

    [TestMethod]
    public void equal_range() {
      c.assign(new int[] { 2, 2, 4, 4, 6, 6, 8, 8 });
      Tuple<int,int> r;
      r = c.equal_range(1, (x,y) => x < y);
      Assert.AreEqual(0, r.Item1); Assert.AreEqual(0, r.Item2);
      r = c.equal_range(2, (x, y) => x < y);
      Assert.AreEqual(0, r.Item1); Assert.AreEqual(2, r.Item2);
      r = c.equal_range(3, (x, y) => x < y);
      Assert.AreEqual(2, r.Item1); Assert.AreEqual(2, r.Item2);
      r = c.equal_range(8, (x, y) => x < y);
      Assert.AreEqual(6, r.Item1); Assert.AreEqual(c.Count, r.Item2);
      r = c.equal_range(10, (x, y) => x < y);
      Assert.AreEqual(c.Count, r.Item1); Assert.AreEqual(c.Count, r.Item2);
    }

    [TestMethod]
    public void find_if() {
      c.assign(new int[] { 2, 2, 4, 4, 6, 6, 8, 8 });
      Assert.AreEqual(2, c.find_if(x => x == 4));
      Assert.AreEqual(c.Count, c.find_if(x => x == 5));
    }

    [TestMethod]
    public void adjacent_find() {
      c.assign(new int[] { 0, 1, 2, 3, 4, 5, 5, 6, 7, 8 });
      Assert.AreEqual(5, c.adjacent_find());
      Assert.AreEqual(4, c.adjacent_find(0,4));
    }

    [TestMethod]
    public void unique() {
      c.assign(new int[] { 0, 2, 2, 3, 4, 5, 5, 6, 7, 8 });
      int pos = c.unique();
      Assert.AreEqual(8, pos);
      Assert.AreEqual(7, c[6]);
      pos = c.unique(0,8);
      Assert.AreEqual(8, pos);
    }

    [TestMethod]
    public void unique_copy() {
      c.assign(new int[] { 0, 2, 2, 3, 4, 5, 5, 6, 7, 8 });
      List<int> result = new List<int>(c.unique_copy());
      Assert.AreEqual(8, result.Count);
      result = new List<int>(result.unique_copy());
      Assert.AreEqual(8, result.Count);
    }

    [TestMethod]
    public void find_first_of() {
      c.assign(new int[] { 0, 2, 4, 6 ,8});
      Assert.AreEqual(2, c.find_first_of(new int[] { 1, 3, 5, 7, 9, 4 }));
      Assert.AreEqual(5, c.find_first_of(new int[] { 1, 3, 5, 7, 9 }));
    }

    [TestMethod]
    public void replace_if() {
      c.assign(new int[] { 0, -1, -2, -3, 4, 5});
      c.replace_if(x => x < 0, 2);
      Assert.IsTrue(c.is_sorted());
    }

    [TestMethod]
    public void fill() {
      c.assign(new int[] { 0, -1, -2, -3, 4 });
      c.fill(2);
      Assert.IsTrue(c.all_of(x => x ==2));
    }

    [TestMethod]
    public void fill_n() {
      c.assign(new int[] { 0, -1, -2, -3, 0 });
      c.fill_n(1,3,2);
      Assert.IsTrue(c.all_of(1,4,x => x ==2));
      Assert.AreEqual(0, c.front());
      Assert.AreEqual(0, c.back());
    }

    private IList<int> c;
  }
}
